#include <stdio.h>
#include "queue.h"
#include "hashtable.h"
#include "mathtable.h"

int x = 0;
int y = 1;
int z = 2;
int w = 194;


boolean_t
show_one(queue_element_t e, queue_pfapply_closure_t cl) 
{
  printf("Item %d == %d\n", *(int*)cl, *(int*)e);
  *(int*)cl = *(int*)cl + 1;
  return TRUE;
}

int 
element_comparator(queue_element_t e1, queue_element_t e2){
  int v1 = *(int *)e1;
  int v2 = *(int *)e2;
  if (v1 < v2){
    return -1;
  }else if(v1 == v2){
    return 0;
  }else{
    return 1;
  }
}

int
hashtable_hash_functon(hashtable_key_t k){
  return *(int *)k;
}

int
hashtable_hash_functon_2(hashtable_key_t k){
  return *(int *)k*2;
}

void 
test_queue(){
  printf("\nTEST QUEUE\n");
  printf("TEST APPEND AND CREATE\n");
  queue_t q = queue_create();
  queue_append(q, &x);
  queue_append(q, &y);
  queue_append(q, &z);
  queue_append(q, &x);
  printf("Queue size is %d\n", queue_size(q));
  int x = 0;
  queue_apply(q, show_one, &x);
  
  printf("\nTEST REVERSE\n");
  printf("BEFORE REVERSE\n");
  printf("Queue size is %d\n", queue_size(q));
  x=0;
  queue_apply(q, show_one, &x);
  queue_reverse(q);
  printf("AFTER REVERSE\n");
  printf("Queue size is %d\n", queue_size(q));
  x=0;
  queue_apply(q, show_one, &x);
  
  printf("\nTEST SORT\n");
  printf("BEFORE SORT\n");
  printf("Queue size is %d\n", queue_size(q));
  x=0;
  queue_apply(q, show_one, &x);
  queue_sort(q, element_comparator);
  printf("AFTER SORT\n");
  printf("Queue size is %d\n", queue_size(q));
  x=0;
  queue_apply(q, show_one, &x);
  
  printf("\nTEST REMOVE\n");
  printf("BEFORE REMOVE\n");
  printf("Queue size is %d\n", queue_size(q));
  x=0;
  int removed=0;
  int *removedp = &removed;
  queue_apply(q, show_one, &x);
  queue_remove(q, (void **)&removedp);
  printf("AFTER REMOVE %d\n", *removedp);
  printf("Queue size is %d\n", queue_size(q));
  x=0;
  queue_apply(q, show_one, &x);
}

void 
test_hashtable(){
  printf("\nTEST HASHTABLE\n");
  printf("CREATE AND ADD\n");
  hashtable_t h = hashtable_create(100, hashtable_hash_functon);
  hashtable_add(h, &z, &y);
  hashtable_add(h, &y, &x);
  hashtable_debug(h);
  
  printf("TEST DUPLICATE INSERTION\n");
  hashtable_add(h, &z, &z);
  hashtable_add(h, &y, &z);
  printf("ITEMS WITH THE SAME KEY AS NEW KEY ARE BEING REPLACED\n");
  hashtable_debug(h);
  
  printf("TEST REMOVE\n");
  hashtable_remove(h, &y);

  printf("AFTER ONE ITEM BEING REMOVED\n");
  hashtable_debug(h);

  printf("TEST LOOK UP KEY = 1 ");
  hashtable_value_t v ;
  int v_int; 
  if (hashtable_lookup(h, &y)==NULL){
    printf("Not found\n");
  }else{
    v = hashtable_lookup(h, &y);
    v_int = *(int *)v;
    printf("found [%d, %d ]\n", v_int, y);
  }

  printf("TEST LOOK UP KEY = 2 ");
  if (hashtable_lookup(h, &z)==NULL){
    printf("Not found\n");
  }else{
    v = hashtable_lookup(h, &z);
    v_int = *(int *)v;
    printf("found [%d, %d]\n", v_int, z);
  }
}

void
test_math_call(){
  printf("\nTEST MATH_CALL\n\n");
  printf("TEST 100 + 200 = ");
  struct args2 a2;
  int result;
  a2.a1 = 100;
  a2.a2 = 200;
  if (math_call(ADD, &a2, &result) < 0) {
    printf("Error");
  } else
    printf("%d\n", result);
  
  printf("TEST 100 - 200 = ");
  if (math_call(SUB, &a2, &result) < 0) {
    printf("Error");
  } else
    printf("%d\n", result);
  
  printf("TEST MEAN OF {100, 50, 75, 20} = ");
  int grades[]={100, 50, 75, 20};
  struct args2_a1p a1;
  a1.a1 = grades;
  a1.a2 = 4;
  if (math_call(MEAN, &a1, &result) < 0) {
    printf("Error");
  } else
    printf("%d\n", result);
  
  printf("TEST SLOPE(100, 200, 150, 400) = ");
  struct args4 slope_arg;
  slope_arg.a1 = 100;
  slope_arg.a2 = 200;
  slope_arg.a3 = 150;
  slope_arg.a4 = 400;
  if (math_call(SLOPE, &slope_arg, &result) < 0) {
    printf("Error");
  } else
    printf("%d\n", result);
}

  
int main(int argc, char* argv[])
{
  test_queue();
  test_hashtable();
  test_math_call();
  
  return 0;
}
